home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 4 / The 640 Meg Shareware Studio CD-ROM Volume IV (Data Express)(1994).ISO / clang / 140_01.zip / ZCASM14.C < prev   
Text File  |  1993-06-26  |  24KB  |  957 lines

  1. /*
  2.  
  3. ZCASM.C    -- a modification of Leor Zolman's CASM.C
  4.  
  5. Copyright (c) 1983 Brian Waldron, Xerox Corporation
  6.  
  7. Altered to accept standard ZILOG Z80 mnemonics and output
  8. short labels for consumption by Microsoft's M80/L80
  9.  
  10.     See the CASM Appendix in the BDSC User's Guide for
  11.     complete information.
  12.  
  13.     Compile and link with:
  14.  
  15.             cc zcasm.c -o -e4300
  16.  
  17.             l2 zcasm
  18.         (or)    clink zcasm
  19.  
  20.     ver. 1.0    7 Oct 83 blw
  21.  
  22.     ver. 1.1    11 Oct 83 blw
  23.             changed DB, DW, DS to DEFB, DEFW, DEFS
  24.             and modified putdir() accordingly
  25.  
  26.     ver. 1.2    17 Oct 83 blw
  27.             cleaned up numerous typos
  28.  
  29.     ver 1.2 released to PD January 1984
  30.  
  31.     ver. 1.3    21 Feb 84 blw
  32.             Allowed underscore(_) in function names
  33.  
  34.     ver. 1.4    27 Mar 85        Lindsay Haisley - Austin, TX.
  35.             Fixed numerous lethal bugs associated with the
  36.             EXTERNAL ZCASM pseudo op.  The list of needed
  37.             functions (*nflist) will now include the name
  38.             of the current function itself, thus avoiding
  39.             multiple lables when EXTERNAL functions are
  40.             referenced. Several initializers in "for" loops 
  41.             were changed to accomodate this modification.
  42.             Two "JMP" statements changed to "JP" statements
  43.             for Z80.  One fprintf2 statement fixed so that 
  44.             the number of arguments agrees with the number 
  45.             of conversion characters.
  46.               
  47. ZCASM is hereby placed in the public domain with the restriction
  48. that it may not be distributed for profit.
  49.  
  50. */
  51.  
  52. #include <bdscio.h>
  53.  
  54. #define TITLE "BDS C CRL-format M80/L80 Preprocessor ver. 1.4\n"
  55.  
  56.  
  57. /*
  58.  *    Customizable definitions:
  59.  */
  60.  
  61. #define DEFUSER    "9/"        /* default user area for include files     */
  62.                 /* make this a null string for "current" */
  63.  
  64. #define DEFDISK "A:"        /* default disk for include files     */
  65. #define ZCASMEXT    ".CZM"    /* extension on input files          */
  66. #define ASMEXT    ".MAC"        /* extension on output files         */
  67. #define SUBFILE "A:ZZZ.FOO"    /* Submit file to erase on error. To not */
  68.                 /* erase any, use a null string ("")     */
  69.  
  70. #define CONTROL_C 3        /* Abort character */
  71. #define EQUMAX    500        /* maximum number of EQU ops         */
  72. #define FUNCMAX    100        /* maximum number of functions         */
  73. #define NFMAX    100        /* maximum number of external functions
  74.                    in one function             */
  75. #define LABMAX    150        /* max number of local labels in 1 func     */
  76. #define TXTBUFSIZE 2000        /* max # of chars for labels and needed
  77.                    function names for a single function     */
  78.  
  79.         /* the following stuff implements a symbol table for
  80.            the purpose of shortening labels to accommidate M80    */
  81.  
  82. #define MAXSYMS 150        /* max # of entries in label        */
  83.                 /* innumeration table            */
  84. #define MAXCHARS 1500        /* max # of chars in lable        */
  85.                 /* innumeration table            */
  86.  
  87. char *str_name[MAXSYMS];    /* array of symbol table entries    */
  88. char sym_buff[MAXCHARS];    /* symbol table                */
  89. char *next_sym;            /* pointer to next empty slot        */
  90. int  current_syms;        /* # of currently defined entries    */
  91.  
  92. /*
  93.  *    End of customizable section
  94.  */
  95.  
  96. #define DIRSIZE    512        /* max # of byte in CRL directory     */
  97. #define TPALOC    0x100        /* base of TPA in your system        */
  98.  
  99.         /* Global data used throughout processing
  100.            of the input file:            */
  101.  
  102. char    fbuf[BUFSIZ];        /* I/O buffer for main input file    */
  103. char    incbuf[BUFSIZ];        /* I/O buffer for included file     */
  104. char    obuf[BUFSIZ];        /* I/O buffer for output file        */
  105. char    *cbufp;            /* ptr to currently active inp buf    */
  106. char    *cfilnam;        /* ptr to name of current inp file    */
  107. char    nambuf[30],        /* filenames for current intput        */
  108.     nambuf2[30],        /* and output files.            */
  109.     onambuf[30];
  110.  
  111. char    *equtab[EQUMAX];    /* table of absolute symbols        */
  112. int    equcount;        /* # of entries in equtab        */
  113.  
  114. char    *fnames[FUNCMAX];    /* list of functions in the file    */
  115. int    fcount;            /* # of entries in fnames        */
  116.  
  117. int    lino,savlino;        /* line number values used for
  118.                    error reporting.            */
  119.  
  120. char    doingfunc;        /* true if now processing a function    */
  121.  
  122. char    errf;            /* true if an error has been detected    */
  123. char    verbose;        /* true to output wordy comments    */
  124. char    blankflag;        /* true if last line processed was null    */
  125.  
  126.         /* Global data used during the processing of a
  127.            single function in the source file:            */
  128.  
  129. char    *nflist[NFMAX];        /* list of needed functions        */
  130. int    nfcount;        /* number of entries in nflist        */
  131.  
  132. struct {
  133.     char *labnam;        /* name of function label        */
  134.     char defined;        /* whether it has been defined yet    */
  135. } lablist[LABMAX];
  136.  
  137. int    labcount;        /* # of local labels in a function    */
  138.  
  139. char    txtbuf[TXTBUFSIZE],    /* where text of needed function     */
  140.     *txtbufp;        /* names and function labels go        */
  141.  
  142. char     linbuf[150],        /* text line buffers    */
  143.     linsav[150],
  144.     workbuf[150],
  145.     pbuf[150], *pbufp;
  146.  
  147. char    *cfunam;    /* pointer to name of current function        */
  148. int    relblc;        /* relocation object count for a function    */
  149.  
  150. char    pastnfs;        /* true if past all needed functions    */
  151.                 /* declarations ("external" pseudo ops)    */
  152.  
  153. int    argcnt;            /* values set by "parse_line" function    */
  154. char    *label,
  155.     *op,
  156.     *argsp,
  157.     *args[40];
  158.  
  159. char     *gpcptr;        /* general-purpose text pointer    */
  160. char    temp_string[20];    /* scratch text buffer        */
  161.  
  162. /*
  163.  * Open main input file, open output file, initialize needed globals
  164.  * and process the file:
  165.  */
  166.  
  167. main(aarghc,aarghv)
  168. char **aarghv;
  169. {
  170.     int i,j,k;
  171.     char c, *inpnam, *outnam;
  172.  
  173.     puts(TITLE);
  174.  
  175.     initequ();        /* init EQU table with reserved words    */
  176.     fcount = 0;        /* haven't seen any functions yet    */
  177.     doingfunc = FALSE;    /* not currently processing a function    */
  178.     errf = FALSE;        /* no errors yet */
  179.     verbose = FALSE;
  180.     inpnam = outnam = NULL;    /* haven't seen any names yet        */
  181.     blankflag = FALSE;    /* haven't just processed a null line    */
  182.  
  183.     while (--aarghc) 
  184.     {
  185.         ++aarghv;    /* bump to next arg text */
  186.         if (**aarghv == '-')
  187.         {
  188.             switch(c = aarghv[0][1])
  189.             {
  190.             case 'C':
  191.                 verbose = 1;
  192.                 break;
  193.  
  194.             case 'O':
  195.                 if (aarghv[0][2])
  196.                     outnam = &aarghv[0][2];
  197.                 else if (--aarghc)
  198.                     outnam = *++aarghv;
  199.                 else goto usage;
  200.                 break;
  201.  
  202.             default: goto usage;
  203.             }
  204.         }
  205.         else
  206.             inpnam = *aarghv;
  207.     }
  208.  
  209.     if (!inpnam) {
  210.   usage:    puts("Usage:\tzcasm [-c] [-o <name>] <filename>\n");
  211.         puts("-C: don't strip comments from input and output\n");
  212.         puts("-O <name>: Call the output file <name>.MAC\n");
  213.         if(*SUBFILE) unlink(SUBFILE);
  214.         exit();
  215.     }
  216.  
  217.     /* set up filenames with proper extensions: */
  218.     for (i = 0; (c = inpnam[i]) && c != '.'; i++)
  219.         nambuf[i] = c;
  220.     nambuf[i] = '\0';
  221.  
  222.     strcpy(onambuf, outnam ? outnam : nambuf);
  223.     strcat(nambuf,ZCASMEXT);    /* input filename */
  224.     cbufp = fbuf;            /* buffer pointer */
  225.     cfilnam = nambuf;        /* current filename pointer */
  226.     if (fopen(cfilnam,cbufp) == ERROR){
  227.         if (*SUBFILE) unlink(SUBFILE);
  228.         exit(printf("Can't open %s\n",cfilnam));
  229.     }    
  230.     if (!hasdot(onambuf))
  231.         strcat(onambuf,ASMEXT);        /* output filename */
  232.     if (fcreat(onambuf,obuf) == ERROR){
  233.         if(*SUBFILE) unlink(SUBFILE);
  234.         exit(printf("Can't create %s\n",onambuf));
  235.     }
  236.                     /* begin writing output file */
  237.     fprintf2(obuf,"\nTPALOC\tEQU\t%04xH\n",TPALOC);
  238.  
  239.     lino = 1;            /* initialize line count */
  240.  
  241.     while (get_line()) {        /* main loop */
  242.         if (kbhit() && getchar() == CONTROL_C)
  243.             abort("Aborted by ^C\n");
  244.         process_line();        /* process lines till EOF */
  245.         lino++;
  246.     }
  247.  
  248.     if (doingfunc)        /* if ends inside a function, error */
  249.         abort("File ends, but last function is unterminated\n");
  250.  
  251.     if (errf)
  252.     {
  253.         puts("Fix those errors and try again...");
  254.         unlink(onambuf);
  255.         if (*SUBFILE) 
  256.             unlink(SUBFILE);
  257.     }
  258.     else
  259.     {
  260.                     /* end of functions    */
  261.         fputs2("\nEND$CRL\tEQU\t$-TPALOC\n",obuf);
  262.         putdir();        /* now put out CRL dir.    */
  263.         fputs2("\tEND\n",obuf);    /* end of ASM file    */
  264.         putc(CPMEOF,obuf);    /* CP/M EOF char.    */
  265.         fclose(cbufp);        /* close input file    */
  266.         fclose(obuf);        /* close output file    */
  267.         printf("%s is ready to be assembled.\n",onambuf);
  268.     }
  269. }
  270.  
  271. /*
  272.  * Get a line of text from input stream, and process
  273.  * "include" ops on the fly:
  274.  */
  275.  
  276. int get_line()
  277. {
  278.     int i;
  279.  
  280. top:    if (!fgets(linbuf,cbufp)) {        /* on EOF: */
  281.         if (cbufp == incbuf) {        /* in an "include" file?*/
  282.             fabort(cbufp->_fd);    /* close the file    */
  283.             cbufp = fbuf;    /* go back to mainline file    */
  284.             cfilnam = nambuf;
  285.             lino = savlino + 1;
  286.             return get_line();
  287.         }
  288.         else return NULL;
  289.     }
  290.  
  291.     if (!verbose)            /* strip commments, default */
  292.     {
  293.         for (i = 0; linbuf[i]; i++)
  294.         {
  295.             if (linbuf[i] == ';')
  296.             {
  297.                 while (i && isspace(linbuf[i-1]))
  298.                     i--;
  299.                 if (!i && blankflag)
  300.                 {
  301.                     lino++;
  302.                     goto top;
  303.                 }
  304.                 strcpy(&linbuf[i], "\n");
  305.                 blankflag = TRUE;
  306.                 break;
  307.             }
  308.             if (linbuf[i] == '\'' || linbuf[i] == '"')
  309.                 break;
  310.         }
  311.         if (!linbuf[i])
  312.             blankflag = FALSE;        
  313.     }
  314.  
  315.     parse_line();                /* not EOF. Parse line */
  316.     if (streq(op,"INCLUDE")  ||        /* check for file inclusion */
  317.         streq(op,"MACLIB")) {
  318.         if (cbufp == incbuf)        /* if already in an include, */
  319.          abort("Only one level of inclusion is supported"); /* error */
  320.         if (!argsp)
  321.          abort("No filename specified");
  322.         cbufp = incbuf;            /* set up for inclusion */
  323.         savlino = lino;
  324.  
  325.         for (i = 0; !isspace(argsp[i]); i++)    /* put null after */
  326.             ;                /* filename      */
  327.         argsp[i] = '\0';
  328.  
  329.         *nambuf2 = '\0';
  330.  
  331.         if (*argsp == '<') {        /* look for magic delimiters */
  332.             strcpy(nambuf2,DEFUSER);
  333.             if (argsp[2] != ':')    /* if no explicit disk given */
  334.                 strcat(nambuf2,DEFDISK); /* then use default */
  335.             strcat(nambuf2,argsp+1);
  336.             if (nambuf2[i = strlen(nambuf2) - 1] == '>')
  337.                 nambuf2[i] = '\0';
  338.         } else if (*argsp == '"') {
  339.             strcpy(nambuf2,argsp+1);
  340.             if (nambuf2[i = strlen(nambuf2) - 1] == '"')
  341.                 nambuf2[i] = '\0';
  342.         } else
  343.             strcpy(nambuf2,argsp);
  344.  
  345.         if (fopen(nambuf2,cbufp) == ERROR) {
  346.             if (!hasdot(nambuf2)) {
  347.                 strcat(nambuf2,".LIB");
  348.                 if (fopen(nambuf2,cbufp) != ERROR)
  349.                     goto ok;
  350.             }                
  351.             printf("Can't open %s\n",nambuf2);
  352.             abort("Missing include file");
  353.         }
  354.  
  355.     ok:    lino = 1;
  356.         cfilnam = nambuf2;
  357.         return get_line();
  358.     }
  359.     return 1;
  360. }
  361.  
  362. parse_line()
  363. {
  364.     int i;
  365.     char c;
  366.  
  367.     label = op = argsp = NULL;
  368.     argcnt = 0;
  369.  
  370.     strcpy2(pbuf,linbuf);
  371.     strcpy2(linsav,linbuf);
  372.     pbufp = pbuf;
  373.  
  374.     if (!*pbufp) return;        /* ignore null lines */
  375.     if (!isspace(c = *pbufp)) {
  376.         if (c == ';')
  377.             return;        /* totally ignore comment lines */
  378.         label = pbufp;        /* set pointer to label    */
  379.         while (isidchr(*pbufp))    /* pass over the label identifier */
  380.             pbufp++;
  381.         *pbufp++ = '\0';    /* place null after the identifier */
  382.     }
  383.  
  384.     skip_wsp(&pbufp);
  385.     if (!*pbufp || *pbufp == ';')
  386.         return;
  387.     op = pbufp;            /* set pointer to operation mnemonic */
  388.     while (isalpha(*pbufp))
  389.         pbufp++;          /* skip over the op         */
  390.     if (*pbufp) *pbufp++ = '\0';    /* place null after the op    */
  391.  
  392.  
  393.                     /* now process arguments    */
  394.     skip_wsp(&pbufp);
  395.     if (!*pbufp || *pbufp == ';')
  396.         return;
  397.     argsp = linsav + (pbufp - pbuf);/* set pointer to arg list */
  398.  
  399.                     /* create vector of ptrs to all args
  400.                        that are possibly relocatable */
  401.     for (argcnt = 0; argcnt < 40;) {
  402.         while (!isidstrt(c = *pbufp))
  403.             if (!c || c == ';')
  404.                 return;
  405.             else
  406.                 pbufp++;
  407.  
  408.         if (isidchr(*(pbufp - 1))) {
  409.             pbufp++;
  410.             continue;
  411.         }
  412.  
  413.         args[argcnt++] = pbufp;            
  414.         while (isidchr(*pbufp)) pbufp++;
  415.         if (*pbufp) *pbufp++ = '\0';
  416.     }
  417.     error("Too many operands in this instruction for me to handle\n");
  418. }
  419.  
  420. process_line()
  421. {
  422.     char *cptr, c;
  423.     int i,j;
  424.  
  425.     if (op) {
  426.             /* check for definitions of global data that will be
  427.                exempt from relocation when encountered in the
  428.                argument field of assembly instructions:        */
  429.  
  430.        if (streq(op,"EQU") || streq(op,"SET") ||
  431.         (!doingfunc &&
  432.             (streq(op,"DEFS") || streq(op,"DEFB") || streq(op,"DEFW")
  433.          || streq(op,"DS") || streq(op,"DB") || streq(op,"DW"))))
  434.        {
  435.         fputs2(linbuf,obuf);
  436.         cptr = sbrk2(strlen(label) + 1);
  437.         strcpy(cptr,label);
  438.         equtab[equcount++] = cptr;
  439.         if (equcount >= EQUMAX)
  440.             abort(
  441.           "Too many EQU lines..increase 'EQUMAX' and recompile ZCASM");
  442.         return;
  443.        }
  444.  
  445.        if (streq(op,"EXTERNAL")) {
  446.         if (!doingfunc) abort(
  447.          "'External's for a function must appear inside the function");
  448.         if (pastnfs) error(
  449.          "Externals must all be together at start of function\n");
  450.         for (i = 0; i < argcnt; i++) {
  451.             nflist[nfcount++] = txtbufp;
  452.             strcpy(txtbufp,args[i]);
  453.             bumptxtp(args[i]);
  454.         }
  455.         if (nfcount >= NFMAX) {
  456.           printf("Too many external functions in function \"%s\"\n",
  457.                     cfunam);
  458.           abort("Change the NFMAX constant and recompile ZCASM");
  459.         }
  460.         return;
  461.        }
  462.  
  463.        if (streq(op,"FUNCTION")) {
  464.         if (!fcount) {
  465.             if (verbose)
  466.             fputs2("\n; dummy external data information:\n",obuf);
  467.  
  468.             fputs2("\tORG\tTPALOC+200H\n",obuf);
  469.             fputs2("\tDEFB\t0,0,0,0,0\n",obuf);
  470.         }
  471.  
  472.         if (doingfunc) {
  473.             printf("'Function' op encountered in a function.\n");
  474.             abort("Did you forget an 'endfunc' op?");
  475.         }
  476.         if (!argcnt)
  477.             abort("A name is required for the 'function' op");
  478.  
  479.         cfunam = sbrk2(strlen(args[0]) + 1);
  480.         fnames[fcount++] = cfunam;
  481.         init_innum();
  482.         strcpy(cfunam,args[0]);
  483.  
  484.         printf("Processing the %s function...          \n",cfunam);
  485.  
  486.         doingfunc = 1;
  487.         txtbufp = txtbuf;
  488.         labcount = 0;
  489.         nfcount = 0;
  490.         pastnfs = 0;
  491.  
  492.         nflist[nfcount++] = txtbufp;  /* Use function name as first */
  493.         strcpy(txtbufp,cfunam);       /* needed func. */
  494.         bumptxtp(cfunam);
  495.  
  496.  
  497.  
  498.         if (verbose)
  499.             fprintf2(obuf,"\n\n; The \"%s\" function:\n",cfunam);
  500.  
  501.         fprintf2(obuf,"BEG$%02d\tEQU\t$-TPALOC\n",fcount-1);
  502.         return;
  503.        }
  504.  
  505.        if (streq(op,"ENDFUNC") || streq(op,"ENDFUNCTION")) {
  506.         if (!doingfunc)
  507.           abort("'Endfunc' op encountered while not in a function");
  508.  
  509.         if (!pastnfs) flushnfs();    /* flush needed function list */
  510.         fprintf2(obuf,"END$%02D\tEQU\t$\n",fcount-1);
  511.         doreloc();             /* flush relocation parameters */
  512.  
  513.         for (i = 0; i < labcount; i++)    /* detect undefined labels */
  514.           if (!lablist[i].defined) {
  515.             printf("The label %s in function %s is undefined\n",
  516.                     lablist[i].labnam,cfunam);
  517.             errf = 1;
  518.           }
  519.         doingfunc = 0;
  520.         return;
  521.        }
  522.     }
  523.                 /* No special pseudo ops, so now process
  524.                    the line as a line of assemby code:     */
  525.  
  526.     if (streq(op,"END")) return;        /* don't allow "end" yet     */
  527.  
  528.     if (!doingfunc || (!label && !op))    /* if nothing interesting on */
  529.         return fputs2(linbuf,obuf);    /* line, ignore it    */
  530.  
  531.     if (!pastnfs)                /* if haven't flushed needed */
  532.         flushnfs();            /* function list yet, do it  */
  533.  
  534.                         /* check for possible label  */
  535.     if (label) {
  536.         fprintf2(obuf,"L%02d$%02d\tEQU\t$-STR$%02d\n",
  537.            fcount-1, innumerate(label), fcount-1);
  538.         for (i=0; linbuf[i]; i++)
  539.             if (isspace(linbuf[i]) || linbuf[i] == ':')
  540.                 break;
  541.             else
  542.                 linbuf[i] = ' ';
  543.         if (linbuf[i] == ':') linbuf[i] = ' ';
  544.         for (i = 0; i < labcount; i++)     /* check if in label table  */
  545.           if (streq(label,lablist[i].labnam)) {           /* if found,  */
  546.             if (lablist[i].defined) {  /* check for redefinition */
  547.                 error("Re-defined label:");
  548.                 printf("%s, in function %s\n",
  549.                         lablist[i].labnam,cfunam);
  550.             }
  551.              else
  552.                 lablist[i].defined = 1;
  553.             goto out;
  554.           }
  555.         lablist[i].labnam = txtbufp;    /* add new entry to    */
  556.         lablist[i].defined = 1;        /* label list        */
  557.         strcpy(txtbufp,label);
  558.         bumptxtp(label);
  559.         labcount++;
  560.     }
  561. out:
  562.     if (!op) return fputs2(linbuf,obuf);    /* if label only, all done   */
  563.  
  564.                         /* if a non-relocatable op,  */
  565.     if (norelop(op)) return fputs2(linbuf,obuf);    /* then we're done   */
  566.  
  567.     if (argcnt && doingfunc)
  568.       for (i = 0; i < argcnt; i++) {
  569.         if (gpcptr = isef(args[i]))
  570.            sprintf(workbuf,"F%02d$%02d-STR$%02d",fcount-1,
  571.             innumerate(gpcptr),fcount-1);
  572.         else if (norel(args[i])) continue;
  573.         else {
  574.             sprintf(workbuf,"L%02d$%02d",fcount-1,
  575.                 innumerate(args[i]));
  576.             for (j = 0; j < labcount; j++)
  577.                 if (streq(args[i],lablist[j].labnam))
  578.                     goto out2;
  579.             lablist[j].labnam = txtbufp;    /* add new entry to */
  580.             lablist[j].defined = 0;        /* label list    */
  581.             strcpy(txtbufp,args[i]);
  582.             bumptxtp(txtbufp);
  583.             labcount++;
  584.         }           
  585.  
  586.     out2:
  587.         if((streq(op,"JR")) || (streq(op,"DJNZ"))){/* odd z80 case */
  588.             sprintf(temp_string,"+STR$%02d",fcount-1);
  589.             strcat(workbuf,temp_string);
  590.         }
  591.         replstr(linbuf, workbuf, args[i] - pbuf, strlen(args[i]));
  592.  
  593.         if (streq(op,"DEFW") || streq(op,"DW")) {
  594.           fprintf2(obuf,"R%02d$%02d\tEQU\t$-STR$%02d\n",
  595.             fcount-1,relblc++,
  596.               fcount-1);
  597.             if (argcnt > 1)
  598.               error("Only one relocatable value allowed per DEFW\n");
  599.         }
  600.         else
  601.             {
  602.             fputs2(linbuf,obuf);
  603.             if ((!streq(op,"JR")) && (!streq(op,"DJNZ")))/* z80  */
  604.                  fprintf2(obuf,"R%02d$%02d\tEQU\t$-2-STR$%02d\n",
  605.                     fcount-1,relblc++,
  606.                     fcount-1);
  607.             return;
  608.             }
  609.         break;
  610.       }
  611.     fputs2(linbuf,obuf);
  612. }
  613.  
  614.  
  615. /*
  616.     Test for ops in which there may be a need
  617.     for generation of relocation parameters. 
  618.     Note that this is somewhat different from the 
  619.     original CASM in that the list contains ops
  620.     that may need attention rather than those
  621.     gauraunteed not to.
  622. */
  623.  
  624. norelop(op)
  625. char *op;
  626. {
  627.     if (streq(op,"LD")) return 0;
  628.     if (streq(op,"CALL")) return 0;
  629.     if (streq(op,"JP")) return 0;
  630.     if (streq(op,"JR")) return 0;
  631.     if (streq(op,"DJNZ")) return 0;
  632.     return 1;
  633. }
  634.  
  635.  
  636. flushnfs()
  637. {
  638.     int i,j, length;
  639.  
  640.     pastnfs = 1;
  641.     relblc = 0;
  642.  
  643.     if (verbose)
  644.         fputs2("\n\n; List of needed functions:\n",obuf);
  645.  
  646.     for (i=1; i < nfcount; i++) {
  647.         strcpy(workbuf,"\tDEFB\t'");
  648.         length = strlen(nflist[i]);
  649.         length = length < 8 ? length : 8;
  650.         for (j = 0; j < length - 1; j++)
  651.             workbuf[7+j] = nflist[i][j];
  652.         workbuf[7+j] = '\0';
  653.         fprintf2(obuf,"%s','%c'+80H\n",workbuf,nflist[i][j]);
  654.     }
  655.  
  656.     fputs2("\tDEFB\t0\n",obuf);
  657.  
  658.     if (verbose)
  659.         fputs2("\n; Length of body:\n",obuf);
  660.  
  661.     fprintf2(obuf,"\tDEFW\tEND$%02d-$-2\n",fcount-1);
  662.  
  663.     if (verbose)
  664.         fputs2("\n; Body:\n",obuf);
  665.  
  666.     fprintf2(obuf,"STR$%02d\tEQU\t$\n",fcount-1);
  667.     if (nfcount > 1) {
  668.         fprintf2(obuf,"R%02d$%02d\tEQU\t$+1-STR$%02d\n",
  669.             fcount-1,relblc++,fcount-1);
  670.         fprintf2(obuf,"\tJP\tSTC$%02d-STR$%02d\n",
  671.             fcount-1,fcount-1);
  672.     }
  673.     fprintf2(obuf,"F%02d$%02d\tEQU\tSTR$%02d\n",fcount-1,
  674.         innumerate(cfunam),fcount-1);
  675.     for (i=1; i < nfcount; i++)
  676.         fprintf2(obuf,"F%02d$%02d:\tJP\t0\n",fcount-1,
  677.             innumerate(nflist[i]));
  678.     fprintf2(obuf,"\nSTC$%02d\tEQU\t$\n",fcount-1);
  679. }
  680.  
  681.  
  682. doreloc()
  683. {
  684.     int i;
  685.  
  686.     if(verbose)
  687.         fputs2("\n; Relocation parameters:\n",obuf);
  688.  
  689.     fprintf2(obuf,"\tDEFW\t%d\n",relblc);
  690.     for(i = 0; i < relblc; i++)
  691.         fprintf2(obuf,"\tDEFW\tR%02d$%02d\n",fcount-1,i);
  692.     fputs2("\n",obuf);
  693. }
  694.  
  695.  
  696. putdir()
  697. {
  698.     int i,j, length;
  699.     int bytecount;
  700.  
  701.     bytecount = 0;
  702.  
  703.     fputs2("\n\tORG\tTPALOC\n\n; Directory:\n",obuf);
  704.     for (i = 0; i < fcount; i++) {
  705.         strcpy(workbuf,"\tDEFB\t'");
  706.         length = strlen(fnames[i]);
  707.         length = length < 8 ? length : 8;
  708.         for (j = 0; j < length - 1; j++)
  709.             workbuf[7+j] = fnames[i][j];
  710.         workbuf[7+j] = '\0';
  711.         fprintf2(obuf,"%s','%c'+80H\n",workbuf,fnames[i][j]);
  712.         fprintf2(obuf,"\tDEFW\tBEG$%02d\n",i);
  713.         bytecount += (length + 2);
  714.     }
  715.     fputs2("\tDEFB\t80H\n\tDEFW\tEND$CRL\n",obuf);
  716.  
  717.     bytecount += 3;
  718.     if (bytecount > DIRSIZE) {
  719.         printf("CRL Directory size will exceed 512 bytes;\n");
  720.         printf("Break the file up into smaller chunks, please!\n");
  721.         exit(-1);
  722.     }
  723. }
  724.  
  725.  
  726. initequ()        /* modified to reflect the z80 mnemonics */
  727. {
  728.     equtab[0] = "A";
  729.     equtab[1] = "B";
  730.     equtab[2] = "C";
  731.     equtab[3] = "D";
  732.     equtab[4] = "E";
  733.     equtab[5] = "H";
  734.     equtab[6] = "L";
  735.     equtab[7] = "SP";
  736.     equtab[8] = "AF";
  737.     equtab[9] = "AND";
  738.     equtab[10]= "OR";
  739.     equtab[11]= "MOD";
  740.     equtab[12]= "NOT";
  741.     equtab[13]= "XOR";
  742.     equtab[14]= "SHL";
  743.     equtab[15]= "SHR";
  744.     equtab[16]= "HL";
  745.     equtab[17]= "BC";
  746.     equtab[18]= "DE";
  747.     equtab[19]= "IX";
  748.     equtab[20]= "IY";
  749.     equtab[21]= "I";
  750.     equtab[22]= "R";
  751.  
  752.     equtab[23]= "Z";
  753.     equtab[24]= "NZ";
  754.     equtab[25]= "P";
  755.     equtab[26]= "M";
  756.     equtab[27]= "PO";
  757.     equtab[28]= "PE";
  758.     equtab[29]= "C";
  759.     equtab[30]= "NC";
  760.  
  761.     equcount = 31;
  762. }
  763.  
  764.  
  765. int isidchr(c)    /* return true if c is legal character in identifier */
  766. char c;
  767. {    
  768.     return isalpha(c) || c == '$' || isdigit(c) || c == '.' || c == '_';
  769. }
  770.  
  771.  
  772. int isidstrt(c)    /* return true if c is legal as first char of identifier */
  773. char c;
  774. {
  775.     return isalpha(c) || c == '_';
  776. }
  777.  
  778.  
  779. int streq(s1, s2)    /* return true if the two strings are equal */
  780. char *s1, *s2;
  781. {
  782.     if (*s1 != *s2) return 0;    /* special case for speed */
  783.     while (*s1) if (*s1++ != *s2++) return 0;
  784.     return (*s2) ? 0 : 1;
  785. }
  786.  
  787.  
  788. skip_wsp(strptr)    /* skip white space at *strptr and modify the ptr */
  789. char **strptr;
  790. {
  791.     while (isspace(**strptr)) (*strptr)++;
  792. }
  793.  
  794.  
  795. strcpy2(s1,s2)    /* copy s2 to s1, converting to upper case as we go */
  796. char *s1, *s2;
  797. {
  798.     while (*s2)
  799.          *s1++ = toupper(*s2++);
  800.     *s1 = '\0';
  801. }
  802.  
  803.  
  804. /*
  805.     General-purpose string-replacement function:
  806.         'string'    is pointer to entire string,
  807.         'insstr'    is pointer to string to be inserted,
  808.         'pos'        is the position in 'string' where 'insstr'
  809.                 is to be inserted
  810.         'lenold'    is the length of the substring in 'string'
  811.                 that is being replaced.
  812. */
  813.  
  814. replstr(string, insstr, pos, lenold)
  815. char *string, *insstr;
  816. {
  817.     int length, i, j, k, x;
  818.  
  819.     length = strlen(string);
  820.     x = strlen(insstr);
  821.     k = x - lenold;
  822.     i = string + pos + lenold;
  823.     if (k) movmem(i, i+k, length - (pos + lenold) + 1);
  824.     for (i = 0, j = pos; i < x; i++, j++)
  825.         string[j] = insstr[i];
  826. }
  827.  
  828.  
  829. error(msg,arg1,arg2)
  830. char *msg;
  831. {
  832.     printf("\n\7%s: %d: ",cfilnam,lino);
  833.     printf(msg,arg1,arg2);
  834.     errf = 1;
  835. }
  836.  
  837.  
  838. abort(msg,arg1,arg2)
  839. char *msg;
  840. {
  841.     error(msg,arg1,arg2);
  842.     putchar('\n');
  843.     if (cbufp == incbuf) fclose(incbuf);
  844.     fclose(fbuf);
  845.     if (*SUBFILE)
  846.         unlink(SUBFILE);
  847.     exit(-1);
  848. }
  849.  
  850.  
  851. sbrk2(n)    /* allocate storage and check for out of space condition */
  852. {
  853.     int i;
  854.     if ((i = sbrk(n)) == ERROR)
  855.         abort("Out of storage allocation space\n");
  856.     return i;
  857. }
  858.  
  859. bumptxtp(str)    /* bump txtbufp by size of given string + 1 */
  860. char *str;
  861. {
  862.     txtbufp += strlen(str) + 1;
  863.     if (txtbufp >= txtbuf + (TXTBUFSIZE - 8))
  864.      abort("Out of text space. Increase TXTBUFSIZE and recompile ZCASM");
  865. }
  866.  
  867.  
  868. int norel(id)    /* return true if identifier is exempt from relocatetion */
  869. char *id;
  870. {
  871.     if (isequ(id)) return 1;
  872.     return 0;
  873. }
  874.  
  875.  
  876. int isequ(str)    /* return true if given string is in the EQU table */
  877. char *str;
  878. {
  879.     int i;
  880.     for (i = 0; i < equcount; i++)
  881.         if (streq(str,equtab[i]))
  882.             return 1;
  883.     return 0;
  884. }
  885.  
  886.  
  887. char *isef(str)    /* return nflist entry if given string is an external */
  888. char *str;    /* function name */
  889. {
  890.     int i;
  891.     for (i = 0; i < nfcount; i++)
  892.         if (streq(str,nflist[i]))
  893.             return nflist[i];
  894.     return 0;
  895. }
  896.  
  897. int hasdot(str)    /* return true if given string has a dot in it */
  898. char *str;
  899. {
  900.     while (*str)
  901.         if (*str++ == '.')
  902.             return TRUE;
  903.     return FALSE;
  904. }
  905.  
  906. fputs2(arg1,arg2)
  907. {
  908.     if (fputs(arg1,arg2) == ERROR)
  909.         abort("Out of disk space for output file.");
  910. }
  911.  
  912. fprintf2(arg1,arg2,arg3,arg4,arg5)
  913. {
  914.     if (fprintf(arg1,arg2,arg3,arg4,arg5) == ERROR)
  915.         abort("Out of disk space for output file.");
  916. }
  917.  
  918.     /* the following two functions manipulate a simple linear
  919.     lookup symbol table to provide SHORT unique identifiers
  920.     for consumption by assemblers that would not allow the long
  921.     labels produced by the original CASM.
  922.     */
  923.  
  924. init_innum()        /* initializes the symbol table to empty */
  925. {
  926.     current_syms = 0;
  927.     next_sym = sym_buff;
  928. }
  929.  
  930. innumerate(string)   /* Assigns a unique # to label to allow assemblers    */
  931. {             /* with only 6 significant label characters to work */
  932.     int i;
  933.     /* look for symbol */
  934.     for(i=0; (i<current_syms) && (i<MAXSYMS); i++)
  935.     {
  936.         if (!strcmp(string,str_name[i])) return i;        
  937.     }
  938.     /* enter symbol */
  939.     if (!((next_sym - sym_buff) < (MAXCHARS-strlen(string)))){
  940.         puts("Out of space in symbol shortening table...");
  941.         unlink(onambuf);
  942.         if (*SUBFILE) unlink(SUBFILE);
  943.         exit();
  944.         }
  945.     if (current_syms == MAXSYMS){
  946.         puts("Too many entries in symbol shortening table...");
  947.         unlink(onambuf);
  948.         if (*SUBFILE) unlink(SUBFILE);
  949.         exit();
  950.         }
  951.     current_syms++;
  952.     str_name[i] = next_sym;
  953.     strcpy(str_name[i],string);
  954.     next_sym += strlen(string) +1;
  955.     return i;
  956. }
  957.